﻿ko.validation.configure({
    parseInputAttributes: true,
    writeInputAttributes: true,
    errorMessageClass: "ierror alert alert-error",
    decorateElement: true,
    errorElementClass: 'btn-danger',
    //messageTemplate: 'errorTemp',
    grouping: {
        deep: true,
        observable: false
    },
    debug: true
});
ko.validation.localize({
    required: 'Bu alan zorunludur.',
    min: 'Please enter a value greater than or equal to {0}.',
    max: 'Please enter a value less than or equal to {0}.',
    minLength: 'Please enter at least {0} characters.',
    maxLength: 'Please enter no more than {0} characters.',
    pattern: 'Please check this value.',
    step: 'The value must increment by {0}',
    email: 'Geçerli bir e-posta adresi giriniz.',
    date: 'Please enter a proper date',
    dateISO: 'Please enter a proper date',
    number: 'Please enter a number',
    digit: 'Please enter a digit',
    phoneUS: 'Please specify a valid phone number',
    equal: 'Values must equal',
    notEqual: 'Please choose another value.',
    unique: 'Please make sure the value is unique.'
});

(function ($, window, document, undefined) {
    var PLUGIN_NAME = "bengBind";

    var opt = {
        url: '',
        data: {},
        onComplete: null,
        onSuccess: null,
        onError: null,
        onBefore: null,
        onAfter: null,
        merge: {},
        mapping: {}
    };

    var DEFAULT_OPTIONS =
    {
        get: opt,
        save: opt,
        remove: opt,
    };

    var pluginInstanceIdCount = 0;

    var I = function (element) {
        return new Internal(element);
    };

    var Internal = function (element) {
        this.$elem = $(element);
        this.elem = element;
        this.data = this.getData();
        this.id = this.data.id;
    };

    Internal.prototype.elementMethods = function () {
        var self = this;
        return {
            'methods':
                {
                    get: function () { self.get(); },
                    save: function (item) {
                        if (ko.validation.utils.isValidatable(item)) {
                            if (item.isValid()) {
                                self.save(item);
                            } else {
                                item.errors.showAllMessages(true);
                            }
                        } else {
                            self.save(item);
                        }
                    },
                    remove: function (item) { self.remove(item); }
                }
        };
    }

    Internal.prototype.init = function (customOptions) {
        var data = this.getData();
        if (!data.initialised) {
            data.initialised = true;
            data.options = $.extend(DEFAULT_OPTIONS, customOptions);
            var d = $.extend(customOptions, DEFAULT_OPTIONS);
            data.options = d;
            this.get();
        }
    };

    Internal.prototype.getData = function () {
        if (!this.$elem.data(PLUGIN_NAME)) {
            this.$elem.data(PLUGIN_NAME, {
                id: pluginInstanceIdCount++,
                initialised: false,
                isbinded: false,
                model: null,
                options: {}
            });
        }
        return this.$elem.data(PLUGIN_NAME);
    };

    Internal.prototype.getEventNs = function (includeDot) {
        return (includeDot !== false ? "." : "") + PLUGIN_NAME + "_" + this.id;
    };

    Internal.prototype.remove = function (item) {
        var self = this;
        var postdata = {};
        postdata = ko.mapping.toJS(item);
        var removeData = $.extend(self.data.options.remove.data, postdata);
        self.data.options.remove.data = removeData;
        this.ajax(self.data.options.remove);
    }

    Internal.prototype.save = function (item) {
        var self = this;
        var postdata = {};
        postdata = ko.mapping.toJS(item);

        var saveData = $.extend(self.data.options.save.data, postdata);
        self.data.options.save.data = saveData;
        this.ajax(self.data.options.save);
    }

    Internal.prototype.get = function (item) {
        var self = this;
        var getData = $.extend(self.data.options.get.data, item);
        self.data.options.get.data = getData;
        this.ajax(self.data.options.get);
    };

    Internal.prototype.showMessage = function (self, message, type) {
        if ($.isArray(message)) {
            var d = "<ul>";
            $.each(message, function (i, item) {
                d = d + "<li>" + item + "</li>";
            });
            d = d + "</ul>";
            message = d;
        }
        bootbox.alert(message, "Tamam");

        return true;
    }
    Internal.prototype.showLoader = function (self) {
        self.$elem.block({ message: null });
    }

    Internal.prototype.hideLoader = function (self) {
        self.$elem.unblock();
    }

    Internal.prototype.destroy = function () {
        this.$elem.unbind(this.getEventNs());
        this.$elem.removeData(PLUGIN_NAME);
    };

    function isArray(o) { return o.isArray || Object.prototype.toString.call(o) === '[object Array]'; };

    Internal.prototype.ajax = function (options) {
        var self = this;

        Internal.prototype.hideLoader(self);

        if (options.onBefore != null && options.onBefore.call(this, self.data.options, options.data) === false) {
            return;
        }

        Internal.prototype.showLoader(self);

        $.ajax({
            url: options.url,
            data: ko.mapping.toJSON(options.data, options.mapping),
            datatype: "json",
            type: "POST",
            cache: false,
            contentType: 'application/json',
            success: function (data) {

                if (data.message) {
                    Internal.prototype.showMessage(self, data.message, "error");
                }

                if (options.onSuccess != null) {
                    options.onSuccess.call(self, self.data.options, data);
                }

                if (!self.data.model) {
                    self.data.model = ko.mapping.fromJS(data);
                } else {
                    ko.mapping.fromJS(data, self.data.model);
                }
                $.extend(true, self.data.model, options.merge);
                $.extend(true, self.data.model, self.elementMethods());

                if (!self.data.isbinded) {
                    ko.validatedObservable(self.data.model);
                    ko.applyBindings(self.data.model, self.elem);
                    self.data.isbinded = true;
                }

                Internal.prototype.hideLoader(self);
                if (options.onAfter != null) {
                    options.onAfter.call(self, self.data.options, data);
                }
            },
            error: function (a, b, c) {
                Internal.prototype.hideLoader(self);
                Internal.prototype.showMessage(self, c, "error");

                if (options.onError != null) {
                    options.onError.call(self);
                }
            },
            complete: options.onComplete
        });
    };

    var publicMethods =
    {
        init: function (customOptions) {
            return this.each(function () {
                I(this).init(customOptions);
            });
        },

        destroy: function () {
            return this.each(function () {
                I(this).destroy();
            });
        },

        get: function (item) {
            return this.each(function () {
                I(this).get(item);
            });
        },

        refresh: function () {
            return this.each(function () {
                I(this).get();
            });
        },

        data: function () {
            return I(this).data;
        }

    };

    $.fn[PLUGIN_NAME] = function (methodOrOptions) {
        return $.each(this, function (i, item) {
            if (!methodOrOptions || typeof methodOrOptions == "object") {
                return publicMethods.init.call($(item), methodOrOptions);
            }
            else {
                var result = publicMethods[methodOrOptions].call($(item), methodOrOptions);
                return result;
            }

        });
    };

})(jQuery, window, document);